package castle.defense.project;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

import android.graphics.Canvas;
import android.view.MotionEvent;

public class ObjectSet {
	private LinkedList<Renderable> safeAddList;
	private LinkedList<Renderable> generic;
	private LinkedList<Enemy> enemies;
	private LinkedList<Projectile> projectiles;
	private Castle castle;
	private Random r;
	private int waveOn;
	private double wavePaintTimer;

	public ObjectSet() {
		generic = new LinkedList<Renderable>();
		enemies = new LinkedList<Enemy>();
		projectiles = new LinkedList<Projectile>();
		safeAddList = new LinkedList<Renderable>();
		r = new Random(System.currentTimeMillis());
		waveOn = 0;
	}

	public boolean waveOver() {
		return enemies.size()==0;
	}

	public void generateNextWave() {
		if(waveOn != 0) {
			Score.incrementScore(250);
		}
		wavePaintTimer = 2;
		waveOn++;
		for(int i = 0; i < 5 + waveOn; i++) {
			add(Enemy.RangedEnemy1(r.nextDouble()*(10+waveOn),r.nextLong()));
		}
		for(int i = 0; i < 5 + waveOn; i++) {
			add(Enemy.MeleeEnemy1(r.nextDouble()*(10+waveOn),r.nextLong()));
		}
		if(waveOn%5==0) {
			add(Enemy.Juggernaut(10, r.nextLong(), waveOn));
		}
	}

	public void setCastle(Castle c) {
		castle = c;
	}

	public void add(Renderable r) {
		if(r!=null)
			safeAddList.add(r);
	}

	private void categorize(Renderable r) {
		if(r instanceof Enemy) {
			enemies.add((Enemy)r);
		} else if(r instanceof Projectile) {
			projectiles.add((Projectile)r);
		} else {
			generic.add(r);
		}
	}

	public void draw(Canvas c) {
		castle.draw(c);
		
		for(Renderable r : generic) {
			r.draw(c);
		}
		
		for(Enemy e : enemies) {
			e.draw(c);
		}
		
		for(Projectile p : projectiles) {
			p.draw(c);
		}

		//This section is for if it is ever implemented such that there are varying heights amongst enemies etc:
//		Collections.sort(generic);
//		Collections.sort(enemies);
//		Collections.sort(projectiles);
//		LinkedList<Enemy> enemyR = new LinkedList<Enemy>();
//		LinkedList<Renderable> genericR = new LinkedList<Renderable>();
//		LinkedList<Projectile> projectileR = new LinkedList<Projectile>();
//		boolean done = false;
//		while(!done) {
//			int s = 7;
//			if(generic.isEmpty()) {
//				s^=1;
//			}
//			if(enemies.isEmpty()) {
//				s^=2;
//			}
//			if(projectiles.isEmpty()) {
//				s^=4;
//			}
//
//			switch(s) {
//			case 7:
//				if(generic.peek().compareTo(enemies.peek()) <= 0 && generic.peek().compareTo(projectiles.peek()) <= 0) {
//					generic.peek().draw(c);
//					genericR.add(generic.poll());
//				} else if(projectiles.peek().compareTo(enemies.peek()) <= 0) {
//					projectiles.peek().draw(c);
//					projectileR.add(projectiles.poll());
//				} else {
//					enemies.peek().draw(c);
//					enemyR.add(enemies.poll());
//				}
//				break;
//			case 6:
//				if(projectiles.peek().compareTo(enemies.peek()) <= 0) {
//					projectiles.peek().draw(c);
//					projectileR.add(projectiles.poll());
//				} else {
//					enemies.peek().draw(c);
//					enemyR.add(enemies.poll());
//				}
//				break;
//			case 5:
//				if(projectiles.peek().compareTo(generic.peek()) <= 0) {
//					projectiles.peek().draw(c);
//					projectileR.add(projectiles.poll());
//				} else {
//					generic.peek().draw(c);
//					genericR.add(generic.poll());
//				}
//				break;
//			case 4:
//				while(!projectiles.isEmpty()) {
//					projectiles.peek().draw(c);
//					projectileR.add(projectiles.poll());
//				}
//				break;
//			case 3:
//				if(generic.peek().compareTo(enemies.peek()) < 0) {
//					generic.peek().draw(c);
//					genericR.add(generic.poll());
//				} else {
//					enemies.peek().draw(c);
//					enemyR.add(enemies.poll());
//				}
//				break;
//			case 2:
//				while(!enemies.isEmpty()) {
//					enemies.peek().draw(c);
//					enemyR.add(enemies.poll());
//				}
//				break;
//			case 1:
//				while(!generic.isEmpty()) {
//					generic.peek().draw(c);
//					genericR.add(generic.poll());
//				}
//				break;
//			default:
//				done=true;
//			}
//		}
//		generic = genericR;
//		enemies = enemyR;
//		projectiles = projectileR;

		if(wavePaintTimer>=0) {
			GraphicsEngine.drawText(c, String.format("Wave %d", waveOn), PE.screenPercentX(50), PE.screenPercentY(50), 10);
		}
	}

	public boolean collisionCheck() {
		for(Projectile p : projectiles) {
			if(!p.offensive) {
				for(Enemy e : enemies) {
					//check enemy collision
					if(PE.collision(p.getPoint(), e.getPoint(), p.size(), e.size())) {
						e.takeDamage(p.attackDamage);
						p.hit();
						break;
					}
				}
			} else {
				//check castle
				if(p.p.y-p.size()<=Castle.top) {
					p.hit();
					castle.takeDamage(p.attackDamage);
				}
			}
		}
		return castle.destroy();
	}

	public void onSingleTap(MotionEvent e) {
		this.onSingleTap(PE.toMetersX(e.getX()), PE.toMetersY(e.getY()));
	}

	public void onSingleTap(double x, double y) {
		if(castle!=null)
			add(castle.basicAttack(x, y));
	}

	public void update(long milli) {
		wavePaintTimer -= milli/1000.0;
		while(!safeAddList.isEmpty()) {
			categorize(safeAddList.poll());
		}
		castle.update(milli);
		for(Iterator i = projectiles.iterator(); i.hasNext(); ) {
			Projectile p = (Projectile)i.next();
			p.update(milli);
			if(p.destroy())
				i.remove();
		}
		for(Iterator i = enemies.iterator(); i.hasNext(); ) {
			Enemy p = (Enemy)i.next();
			Projectile proj = p.updateE(milli);
			if(p.destroy()) {
				Score.incrementScore(p.getPointValue());
				i.remove();
			}
			add(proj);
		}
		for(Iterator i = generic.iterator(); i.hasNext(); ) {
			Renderable p = (Renderable)i.next();
			p.update(milli);
			if(p.destroy())
				i.remove();
		}

		if(waveOver()) {
			generateNextWave();
		}
	}
}
